package com.camel.core.service;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.camel.core.entity.BasePaginationEntity;
import com.camel.core.entity.IFilter;
import com.camel.core.entity.IParams;
import com.camel.core.enums.EntityStatus;
import com.google.common.base.CaseFormat;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author camel
 * @param <M>
 * @param <T>
 */
public abstract class AbstractBaseCommonService<M extends BaseMapper<T>, T extends BasePaginationEntity> extends ServiceImpl<M, T> implements BaseCommonService<T> {

    public static final String PARAM_ORDER_DESC_KEY = "desc";
    public static final String PARAM_ORDER_ASC_KEY = "asc";



    public QueryWrapper<T> buildWrapper(IParams params) {
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        for (IFilter filter : params.getFilters()) {
            if (!StringUtils.isEmpty(filter.getFieldName())) {
                if (!StringUtils.isEmpty(filter.getCompare())) {
                    String fieldName = filter.getFieldName();
                    fieldName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName);
                    switch (filter.getCompare()) {
                        case ">":
                            wrapper.gt(fieldName, filter.getFieldValue());
                            break;
                        case "<":
                            wrapper.lt(fieldName, filter.getFieldValue());
                            break;
                        case ">=":
                            wrapper.ge(fieldName, filter.getFieldValue());
                            break;
                        case "<=":
                            wrapper.le(fieldName, filter.getFieldValue());
                            break;
                        case "!=":
                            wrapper.ne(fieldName, filter.getFieldValue());
                            break;
                        case "=":
                            if(!StringUtils.isEmpty(filter.getFieldValue())) {
                                wrapper.eq(fieldName, filter.getFieldValue());
                            }
                            break;
                        case "like":
                            if(!StringUtils.isEmpty(filter.getFieldValue())) {
                                wrapper.like(fieldName, filter.getFieldValue());
                            }
                            break;
                        case "likeLeft":
                            wrapper.likeLeft(fieldName, filter.getFieldValue());
                            break;
                        case "likeRight":
                            wrapper.likeRight(fieldName, filter.getFieldValue());
                            break;
                        case "bt":
                            Object fieldValue = filter.getFieldValue();
                            if (!ObjectUtils.isEmpty(fieldValue)) {
                                String sv = (String) fieldValue;
                                if (sv.contains(",")) {
                                    wrapper.between(fieldName, sv.split(",")[0], sv.split(",")[1]);
                                }
                            }
                            break;
                        case "nbt":
                            Object nBtValue = filter.getFieldValue();
                            if (!ObjectUtils.isEmpty(nBtValue)) {
                                String sv = (String) nBtValue;
                                if (sv.contains(",")) {
                                    wrapper.notBetween(fieldName, sv.split(",")[0], sv.split(",")[1]);
                                }
                            }
                            break;
                        case "in":
                            if (!ObjectUtils.isEmpty(filter.getFieldValue())) {
                                wrapper.in(fieldName, CollectionUtils.arrayToList(filter.getFieldValue().toString().split(",")));
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }

        if (!ObjectUtils.isEmpty(params.getOrderBy())) {
            if (params.getOrderBy().endsWith(PARAM_ORDER_DESC_KEY)) {
                wrapper.orderByDesc(params.getOrderBy().replace("desc", ""));
            } else if (params.getOrderBy().endsWith(PARAM_ORDER_ASC_KEY)) {
                wrapper.orderByAsc(params.getOrderBy().replace(PARAM_ORDER_ASC_KEY, ""));
            }
        }
        return wrapper;
    }

    @Override
    public List<T> list(IParams params) {
        return list(buildWrapper(params));
    }

    @Override
    public boolean save(T entity) {
        entity.setCreateAt(new Date());
        entity.setUpdateAt(new Date());
        entity.setUpdator(StpUtil.getLoginIdAsInt());
        entity.setCreator(StpUtil.getLoginIdAsInt());
        entity.setStatus(EntityStatus.NORMAL);
        return super.save(entity);
    }

    @Override
    public boolean saveOrUpdate(T entity) {
        if (null == entity) {
            return false;
        } else {
            TableInfo tableInfo = TableInfoHelper.getTableInfo(this.entityClass);
            Assert.notNull(tableInfo, "error: can not execute. because can not find cache of TableInfo for entity!", new Object[0]);
            String keyProperty = tableInfo.getKeyProperty();
            Assert.notEmpty(keyProperty, "error: can not execute. because can not find column for id from entity!", new Object[0]);
            Object idVal = ReflectionKit.getFieldValue(entity, tableInfo.getKeyProperty());
            if(!com.baomidou.mybatisplus.core.toolkit.StringUtils.checkValNull(idVal) && !Objects.isNull(this.getById((Serializable)idVal))) {
                entity.setUpdator(StpUtil.getLoginIdAsInt());
                entity.setUpdateAt(new Date());
            } else {
                entity.setStatus(EntityStatus.NORMAL);
                entity.setCreator(StpUtil.getLoginIdAsInt());
                entity.setUpdator(StpUtil.getLoginIdAsInt());
                entity.setUpdateAt(new Date());
                entity.setCreateAt(new Date());
            }
            return super.saveOrUpdate(entity);
        }
    }
}
